package top.fullj.chain;

import top.fullj.ctx.ContextBase;

import javax.annotation.Nonnull;
import java.util.List;
import java.util.Map;

/**
 * @author bruce.wu
 * @since 2021/6/17 17:24
 */
@SuppressWarnings({"unused", "UnusedReturnValue"})
public interface Chain extends Iterable<Map.Entry<String, Handler>> {

    class Context extends ContextBase {

        private static final Object REQUEST_KEY = "_X-REQ_";
        private static final Object RESPONSE_KEY = "_X-RSP_";

        public Context(Object request, Object response) {
            this(false, request, response);
        }

        public Context(boolean threadsafe, Object request, Object response) {
            super(threadsafe);
            setRequest(request);
            setResponse(response);
        }

        public <T> T getRequest() {
            return getAttr(REQUEST_KEY);
        }

        public void setRequest(Object request) {
            setAttr(REQUEST_KEY, request);
        }

        public <T> T getResponse() {
            return getAttr(RESPONSE_KEY);
        }

        public void setResponse(Object response) {
            setAttr(RESPONSE_KEY, response);
        }

    }

    void proceed(Chain.Context ctx) throws HandlerException;

    @Nonnull
    Chain origin();

    @Nonnull
    List<String> names();

    @Nonnull
    Map<String, Handler> toMap();

    Chain addFirst(Handler handler);

    Chain addFirst(String name, Handler handler);

    Chain addFirst(Handler...handlers);

    Chain addLast(Handler handler);

    Chain addLast(String name, Handler handler);

    Chain addLast(Handler...handlers);

    Chain addBefore(String originName, Handler handler);

    Chain addBefore(Class<? extends Handler> type, Handler handler);

    Chain addBefore(String originName, String name, Handler handler);

    Chain addAfter(String originName, Handler handler);

    Chain addAfter(Class<? extends Handler> type, Handler handler);

    Chain addAfter(String originName, String name, Handler handler);

    Chain remove(Handler handler);

    Handler remove(String name);

    Handler remove(Class<? extends Handler> type);

    Handler removeFirst();

    Handler removeLast();

    Chain replace(Handler originHandler, String name, Handler handler);

    Handler replace(String originName, String name, Handler handler);

    Handler replace(Class<? extends Handler> type, Handler handler);

    Handler replace(Class<? extends Handler> type, String name, Handler handler);

    Handler first();

    Handler last();

    Handler get(String name);

    Handler get(Class<? extends Handler> type);

}
